package meiyunting.shiwuzhaoling.service;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * 熔断器服务
 * 封装Resilience4j熔断器相关功能
 */
@Slf4j
@Service
public class CircuitBreakerService {

    @Autowired
    private CircuitBreakerRegistry circuitBreakerRegistry;
    
    @Autowired
    private RetryRegistry retryRegistry;
    
    // 记录服务调用失败次数
    private final Map<String, AtomicInteger> failureCounters = new HashMap<>();
    
    /**
     * 使用熔断器执行服务调用
     * @param serviceId 服务ID
     * @param supplier 服务调用逻辑
     * @param fallback 降级逻辑
     * @return 服务调用结果或降级结果
     */
    public <T> T executeWithCircuitBreaker(String serviceId, Supplier<T> supplier, Supplier<T> fallback) {
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceId);
        Retry retry = retryRegistry.retry(serviceId);
        
        // 记录熔断器状态
        CircuitBreaker.State state = circuitBreaker.getState();
        log.info("服务 [{}] 的熔断器状态: {}", serviceId, state);
        
        // 使用熔断器和重试机制包装服务调用
        Supplier<T> decoratedSupplier = CircuitBreaker.decorateSupplier(circuitBreaker, supplier);
        decoratedSupplier = Retry.decorateSupplier(retry, decoratedSupplier);
        
        try {
            T result = decoratedSupplier.get();
            // 调用成功，重置失败计数
            resetFailureCount(serviceId);
            return result;
        } catch (Exception e) {
            log.error("服务 [{}] 调用失败: {}", serviceId, e.getMessage());
            // 增加失败计数
            incrementFailureCount(serviceId);
            // 返回降级结果
            return fallback.get();
        }
    }
    
    /**
     * 获取熔断器状态
     * @param serviceId 服务ID
     * @return 熔断器状态信息
     */
    public Map<String, Object> getCircuitBreakerStatus(String serviceId) {
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceId);
        Map<String, Object> status = new HashMap<>();
        
        status.put("state", circuitBreaker.getState().toString());
        status.put("failureRate", circuitBreaker.getMetrics().getFailureRate());
        status.put("slowCallRate", circuitBreaker.getMetrics().getSlowCallRate());
        status.put("numberOfBufferedCalls", circuitBreaker.getMetrics().getNumberOfBufferedCalls());
        status.put("numberOfFailedCalls", circuitBreaker.getMetrics().getNumberOfFailedCalls());
        status.put("numberOfSlowCalls", circuitBreaker.getMetrics().getNumberOfSlowCalls());
        status.put("numberOfSuccessfulCalls", circuitBreaker.getMetrics().getNumberOfSuccessfulCalls());
        status.put("failureCount", getFailureCount(serviceId));
        
        return status;
    }
    
    /**
     * 重置熔断器状态
     * @param serviceId 服务ID
     */
    public void resetCircuitBreaker(String serviceId) {
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceId);
        circuitBreaker.reset();
        resetFailureCount(serviceId);
        log.info("服务 [{}] 的熔断器已重置", serviceId);
    }
    
    /**
     * 获取失败计数
     */
    private int getFailureCount(String serviceId) {
        return failureCounters.computeIfAbsent(serviceId, k -> new AtomicInteger(0)).get();
    }
    
    /**
     * 增加失败计数
     */
    private void incrementFailureCount(String serviceId) {
        failureCounters.computeIfAbsent(serviceId, k -> new AtomicInteger(0)).incrementAndGet();
    }
    
    /**
     * 重置失败计数
     */
    private void resetFailureCount(String serviceId) {
        failureCounters.computeIfAbsent(serviceId, k -> new AtomicInteger(0)).set(0);
    }
} 